package com.linden.std.service.auth;

import com.linden.std.constant.CommonConstant;
import com.linden.std.domain.po.SysUser;
import com.linden.std.enums.ExceptionEnums;
import com.linden.std.exception.CustomException;
import com.linden.std.util.RedisTemplateUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.Date;

/**
 * Token服务
 */
@Slf4j
@Service
public class TokenService {
    
    @Value("${std.security.token.secret-key:stdSecretKey123456}")
    private String secretKey;
    
    @Value("${std.security.token.access-timeout:7200}")
    private Long accessTimeout;
    
    @Value("${std.security.token.refresh-timeout:2592000}")
    private Long refreshTimeout;
    
    @Autowired
    private RedisTemplateUtil redisTemplateUtil;

    public String generateAccessToken(SysUser user) {
        return generateToken(user, "access", accessTimeout);
    }

    public String generateRefreshToken(SysUser user) {
        return generateToken(user, "refresh", refreshTimeout);
    }

    private String generateToken(SysUser user, String tokenType, Long timeout) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + timeout * 1000);
        
        return Jwts.builder()
            .setSubject(user.getUsername())
            .setIssuedAt(now)
            .setExpiration(expiryDate)
            .claim("userId", user.getId())
            .claim("username", user.getUsername())
            .claim("tokenType", tokenType)
            .signWith(SignatureAlgorithm.HS512, secretKey)
            .compact();
    }

    public boolean validateToken(String token) {
        try {
            if (isBlacklisted(token)) {
                return false;
            }
            Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public Claims parseToken(String token) {
        try {
            return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(token)
                .getBody();
        } catch (Exception e) {
            throw new CustomException(ExceptionEnums.TOKEN_INVALID);
        }
    }

    public void addToBlacklist(String token, long expirationTime) {
        long ttl = expirationTime - System.currentTimeMillis() / 1000;
        if (ttl > 0) {
            String key = CommonConstant.LOGIN_ATTEMPT_PREFIX + DigestUtils.md5DigestAsHex(token.getBytes());
            redisTemplateUtil.set(key, "1", ttl);
        }
    }

    public boolean isBlacklisted(String token) {
        String key = CommonConstant.LOGIN_ATTEMPT_PREFIX + DigestUtils.md5DigestAsHex(token.getBytes());
        return redisTemplateUtil.hasKey(key);
    }
}